<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>QuickSort Viewer</title>
    <link rel="stylesheet" type="text/css" href="main.css" />
    <link rel="stylesheet" type="text/css" href="https://www.layuicdn.com/layui/css/layui.css" />
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="jquery-1.11.3.min.js"></script>
    <script src="https://www.layuicdn.com/layui/layui.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/layer/2.3/layer.js"></script>
</head>
<body>
<style>
    [v-cloak] {
        display: none;
    }
</style>
<div id="app" class="layui-anim layui-anim-fadein" v-cloak>
    <div class="header" v-cloak>
        <span style="color: #f0f0f0">QuickSort Viewer</span>
        <div class= "flex-box">
            <div class="layui-inline">
                <div class="layui-input-inline">
                    <input type="text"  autocomplete="off" placeholder="请输入整数以',' 隔开" class="layui-input"  v-model="list_str">
                </div>
            </div>
            <div class="layui-inline" style="margin-left: 10px">
                <div class="layui-btn-group">
                    <button type="button" class="layui-btn layui-btn-primary layui-btn-sm" :class="{'layui-btn-disabled':isStart && !isPause}" @click="isStart?refuse_sort():start_sort()"><i class="layui-icon layui-icon-play"></i></button>
                    <button type="button" class="layui-btn layui-btn-primary layui-btn-sm" :class="{'layui-btn-disabled':!(!isPause && isStart)}" @click="pause_sort()"><i class="layui-icon layui-icon-pause
"></i></button>
                    <button type="button" class="layui-btn layui-btn-primary layui-btn-sm" :class="{'layui-btn-disabled':!isStart}" @click="stop_sort()"><i class="layui-icon layui-icon-delete
" ></i></button>
                    <button type="button" class="layui-btn layui-btn-primary layui-btn-sm" :class="{'layui-btn-disabled':isStart}"  @click="get_random()"><i class="layui-icon layui-icon-set
"></i></button>
                </div>
            </div>

        </div>
    </div>

    <div class="container " v-cloak>
        <div class="left" id="view">
            <div  class="canvas" v-if="isStart" :style="{ height:scale + 'px'}">
                <div :class="{box:true}" v-for="(item,index) in sentinel"
                     :style="{ width:scale + 'px',height:scale + 'px',transform: 'translateX(' +  item.index * 100 + '%)' }">
                    <div :class="{item:true,select:item.select,disable:item.disable}">{{item.name}}</div>
                </div>
            </div>

            <div  class="canvas" :style="{ height:scale + 'px'}">
                <div :class="{box:true}" v-for="(item,index) in list"
                     :style="{width:scale + 'px',height:scale + 'px', transform: 'translateX(' +  item['index'] * 100 + '%)' }">
                    <div :class="{item:true,select:item.select,disable:item.disable}" >{{item.value}}</div>
                </div>
            </div>
        </div>
        <div class="right">
            <div class="info">
                <p>当前步骤:</p>
                <p>{{info}}</p>
            </div>

            <div class="author">
                <div  style="width:100px;height: 100px;border-radius:50px;margin-bottom:20px;background-image: url(https://qlogo4.store.qq.com/qzone/502595347/502595347/100?1564448779);"></div>
                <p> 1817053 张弛 </p>
            </div>

            <button type="button" class="layui-btn layui-btn-fluid" onclick="clickme();">关于可视化的说明</button>
        </div>
    </div>

</div>


<script>
    function clickme() {
        location.href='https://blog.csdn.net/shipsail/article/details/106134796';
    }

    function _alert(msg,icon) {
        layer.msg(msg, {icon: icon});
    }

    var sleep= 500;
    var ARRAY = [3,100,2,1,4,5,9]; // global var
    var INDEX = [0,1,2,3,4,5,6];

    function swap(id1,id2) {
        var t;
        t = ARRAY[id1];
        ARRAY[id1] = ARRAY[id2];
        ARRAY[id2] = t;
        t = INDEX[id1];
        INDEX[id1] = INDEX[id2];
        INDEX[id2] = t;
    }
    
    function * f(left,right) {
        if (left >= right) {
            if (left == right)yield {'method':'disable','data':INDEX[left]};
            return;
        }
        var i,j,temp;
        i = left;j = right;
        temp  = ARRAY[left];

        yield {'method':'moves','data':[[1,left],[2,right]]};
        yield {'method':'select','data':INDEX[left]};

        while(i != j){
            while(ARRAY[j] >= temp && i < j) {
                j--;
                yield {'method':'move','data':[2,j]};
            }
            while(ARRAY[i] <= temp && i < j) {
                i++;
                yield {'method':'move','data':[1,i]};
            }
            if(i < j)
            {
                swap(i,j);
                yield {'method':'selects','data':[INDEX[i],INDEX[j]]};
                yield {'method':'swap','data':[INDEX[i],INDEX[j]]};
                yield {'method':'deselects','data':[INDEX[i],INDEX[j]]};
            }
        }
        // yield {'method':'deselect','data':INDEX[left]};
        yield {'method':'disable','data':INDEX[left]};
        swap(left,i);
        yield {'method':'selects','data':[INDEX[left],INDEX[i]]};
        yield {'method':'swap','data':[INDEX[left],INDEX[i]]};
        yield {'method':'deselects','data':[INDEX[left],INDEX[i]]};
        // 递归委托
        yield * f(left,i - 1);
        yield * f(i + 1,right);
    }



    var App = new Vue({
        el:'#app',
        data(){
            return{
                list_str :'', // 与用户交互的字符串
                list : [], // 排序使用的数组 [{index,value}]
                iter:null, // 迭代器
                isStart:false, // 是否开启
                isPause:false, // 是否暂停
                sentinel:[{'name':'哨兵1','index':0},{'name':'哨兵2','index':0}],
                queue : [],
                info : '已停止',
                scale:0,
            }
        },
        methods:{
            reset_list(){
                this.list_str = '3,100,2,1,4,5,9'
            },
            init_sort(){
                // sort init
                this.iter = f(0,this.list.length - 1);
                ARRAY = [];
                INDEX = [];
                this.sentinel = [{'name':'哨兵1','index':0},{'name':'哨兵2','index':this.list.length - 1}];
                for (let i = 0; i < this.list.length; i++) {
                    this.list[i].index = i;
                    this.list[i].select = false;
                    this.list[i].disable = false;
                    ARRAY.push(this.list[i].value);
                    INDEX.push(i);
                }
            },
            start_sort(){
                if(this.isStart && !this.isPause) return;
                if (!this.isPause) {
                    this.init_sort();
                }
                this.isStart = true;
                this.isPause = false;
                var start = ()=>{
                    if(!this.isStart || this.isPause) return;
                    var i = this.iter.next();
                    if (!i.done){
                        console.log(i.value.method,i.value.data);
                        var a,b,t;
                        if(i.value.method == 'swap'){
                            a = i.value.data[0];
                            b = i.value.data[1];
                            this.set_info("交换(" + this.list[a].index.toString()+ " | " + + this.list[b].index.toString()+ ")" );
                            t = this.list[a].index;
                            this.list[a].index = this.list[b].index;
                            this.list[b].index = t;

                        }else if(i.value.method == 'move'){
                            a = i.value.data[0];
                            b = i.value.data[1];
                            this.sentinel[a - 1].index = b;
                            this.set_info("哨兵[" + a.toString()+ "] move --> " + b.toString());
                        }else if(i.value.method == 'moves'){
                            a = i.value.data;
                            for (let j = 0; j < a.length; j++) {
                                this.sentinel[a[j][0] - 1].index = a[j][1];
                            }

                        }else if(i.value.method == 'select'){
                            a = i.value.data;
                            this.list[a].select = true;
                            this.set_info("选择基准点(" + this.list[a].index.toString()+ ")" );
                        }else if(i.value.method == 'selects'){
                            a = i.value.data;
                            for (let j = 0; j < a.length; j++) {
                                this.list[a[j]].select = true;
                            }
                        }else if(i.value.method == 'deselect'){
                            a = i.value.data;
                            this.list[a].select = false;
                        }else if(i.value.method == 'deselects'){
                            a = i.value.data;
                            for (let j = 0; j < a.length; j++) {
                                this.list[a[j]].select = false;
                            }
                        }else if(i.value.method == 'disable'){
                            a = i.value.data;
                            this.list[a].disable = true;
                        }
                    }else if(i.done){
                        this.stop_sort();
                    }
                    setTimeout(start,sleep);
                };
                setTimeout(start,0);

            },
            stop_sort(){
                if(!this.isStart) return;
                this.isStart = false;
                this.isPause = false;
                this.set_info("已停止");
                _alert("排序已结束",1);
            },
            refuse_sort(){
                if(!this.isStart || !this.isPause) return;
                this.start_sort();
            },
            pause_sort(){
                if(!this.isStart || this.isPause) return;
                this.isPause = true;
                this.set_info("已暂停");
            },
            get_random(){
                if (this.isStart) return;
                var num = Math.round(Math.random() * 2) + 10; // 10 - 12
                var arr = [];
                for (let i = 0; i < num; i++) {
                    arr.push(Math.round(Math.random() * 1000)); // 1000以内
                }
                this.list_str = arr.toString();
            },
            set_info(msg){
                this.info = msg;
            }
        },
        watch:{
            // 变量监听
            list_str: function (val,ordval) {
                this.list = [];
                let list = val.split(',').map(obj => parseInt(obj));// 映射为整数数组
                for (let i = 0; i < list.length; i++) {
                    this.list.push({'index':i,'value':list[i],'select':false,'disable':false});
                }
                var w = document.getElementById("view").offsetWidth;
                this.scale = parseInt(w / this.list.length);
                console.log(this.list);
            }
        }
    })


    setTimeout(()=>{
        App.reset_list();
        App.get_random();
        _alert("Hello!!!",6);
    },0);

</script>


</body>
</html>